#MySQL SQL转换
本文档基于MySQL8.0已有语法,根据SQL转换对以下语法进行了规则化的转换。
# 概述
在YMP的任务评估阶段,会对源数据库中的对象(表、视图、约束、索引等)进行兼容性评估,以确保源端数据库对象可以成功迁移到目标数据库。在评估阶段,会尝试获取源端数据库对象的DDL并在目标数据库执行。如果执行成功,则说明此对象为原生兼容,无需进行特殊处理。否则,会使用SQL转换工具根据源端到目标端数据库的语法转换规则对此DDL进行语法转换,以适配目标数据库的语法特性。如果转换成功,会尝试在目标数据库中执行转换后的SQL,执行成功则说明此对象为自动兼容,可以进行迁移。
# CREATE TABLE
序号 | MySQL语法/关键字 | YashanDB22.2转换规则 | YashanDB23.1转换规则 |
---|---|---|---|
1 | 临时表TEMPORARY关键字 | 转为全局临时表 | 同左 |
2 | create_definition: { col_name column_definition | {INDEX | KEY} [index_name] [index_type] (key_part,...) [index_option] ... (表内索引) | {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...) [index_option] ... | [CONSTRAINT [symbol]] PRIMARY KEY (表内主键) [index_type] (key_part,...) [index_option] ... | [CONSTRAINT [symbol]] UNIQUE [INDEX | KEY] (索引定义) [index_name] [index_type] (key_part,...) [index_option] ... | [CONSTRAINT [symbol]] FOREIGN KEY (外键引用定义) [index_name] (col_name,...) reference_definition (外键引用定义) | check_constraint_definition } | 只保留col_name column_definition | 同左 |
3 | column_definition: { data_type [NOT NULL | NULL] [VISIBLE | INVISIBLE] [AUTO_INCREMENT] [UNIQUE [KEY]] [[PRIMARY] KEY] [COMMENT 'string'] (列注释信息) [COLLATE collation_name] [COLUMN_FORMAT {FIXED | DYNAMIC | DEFAULT}] [ENGINE_ATTRIBUTE [=] 'string'] [SECONDARY_ENGINE_ATTRIBUTE [=] 'string'] [STORAGE {DISK | MEMORY}] [reference_definition] [check_constraint_definition] | data_type [COLLATE collation_name] [GENERATED ALWAYS] AS (expr) [VIRTUAL | STORED] [NOT NULL | NULL] [VISIBLE | INVISIBLE] [UNIQUE [KEY]] [[PRIMARY] KEY] [COMMENT 'string'] [reference_definition] [check_constraint_definition] } | 只保留data_type,和DEFAULT 。 AUTO_INCREMENT和comment语法会转化为单独的语句,分别跟随在表定义前和后。 注:仅部分数据类型可以正常转出。 | 同左 |
4 | table_option: { AUTOEXTEND_SIZE [=] value | AUTO_INCREMENT [=] value | AVG_ROW_LENGTH [=] value | [DEFAULT] CHARACTER SET [=] charset_name | CHECKSUM [=] {0 | 1} | [DEFAULT] COLLATE [=] collation_name | COMMENT [=] 'string' | COMPRESSION [=] {'ZLIB' | 'LZ4' | 'NONE'} | CONNECTION [=] 'connect_string' | {DATA | INDEX} DIRECTORY [=] 'absolute path to directory' | DELAY_KEY_WRITE [=] {0 | 1} | ENCRYPTION [=] {'Y' | 'N'} | ENGINE [=] engine_name | ENGINE_ATTRIBUTE [=] 'string' | INSERT_METHOD [=] { NO | FIRST | LAST } | KEY_BLOCK_SIZE [=] value | MAX_ROWS [=] value | MIN_ROWS [=] value | PACK_KEYS [=] {0 | 1 | DEFAULT} | PASSWORD [=] 'string' | ROW_FORMAT [=] {DEFAULT | DYNAMIC | FIXED | COMPRESSED | REDUNDANT | COMPACT} | START TRANSACTION | SECONDARY_ENGINE_ATTRIBUTE [=] 'string' | STATS_AUTO_RECALC [=] {DEFAULT | 0 | 1} | STATS_PERSISTENT [=] {DEFAULT | 0 | 1} | STATS_SAMPLE_PAGES [=] value | tablespace_option | UNION [=] (tbl_name[,tbl_name]...) } | AUTO_INCREMENT [=] value会换为表前定义序列的start with的起始值。 COMMENT [=] 'string'会转为表后的单独comment语句 tablespace_option初始获取可能会带有注释形式,移除注释(YMP处理),tablespace正常转换出来(保留名字)。 | 同左 |
5 | tablespace_option: TABLESPACE tablespace_name [STORAGE DISK] | [TABLESPACE tablespace_name] STORAGE MEMORY | 只保留表空间名称,删除[STORAGE DISK] 如果表空间名称为innodb_file_per_table,则表示为默认表空间,因此转换时会丢弃表空间名称信息 | 同左 |
6 | partition_definition: PARTITION partition_name 分区定义语法 [VALUES {LESS THAN {(expr | value_list) | MAXVALUE} | IN (value_list)}] [[STORAGE] ENGINE [=] engine_name] [COMMENT [=] 'string' ] [DATA DIRECTORY [=] 'data_dir'] [INDEX DIRECTORY [=] 'index_dir'] [MAX_ROWS [=] max_number_of_rows] [MIN_ROWS [=] min_number_of_rows] [TABLESPACE [=] tablespace_name] [(subpartition_definition [, subpartition_definition] ...)] | 只保留YashanDB支持的分区定义信息, [[STORAGE] ENGINE [=] engine_name] [COMMENT [=] 'string' ] [DATA DIRECTORY [=] 'data_dir'] [INDEX DIRECTORY [=] 'index_dir'] [MAX_ROWS [=] max_number_of_rows] [MIN_ROWS [=] min_number_of_rows] 都会被删除 分区信息初始获取可能会带有注释形式,移除注释(YMP处理) | 同左 |
7 | subpartition_definition: 子分区定义语法 SUBPARTITION logical_name [[STORAGE] ENGINE [=] engine_name] [COMMENT [=] 'string' ] [DATA DIRECTORY [=] 'data_dir'] [INDEX DIRECTORY [=] 'index_dir'] [MAX_ROWS [=] max_number_of_rows] [MIN_ROWS [=] min_number_of_rows] [TABLESPACE [=] tablespace_name] | 22.2无该语法 ,转换时删除 | 23.1保留子分区转换输出 |
8 | ON UPDATE CURRENT_TIMESTAMP(n) | 转换成触发器 | 同左 |
# CREATE VIEW
序号 | MySQL语法/关键字 | YashanDB22.2转换规则 | YashanDB23.1转换规则 |
---|---|---|---|
9 | CREATE [OR REPLACE] [SQL SECURITY { DEFINER | INVOKER }] VIEW view_name [(column_list)] AS | [SQL SECURITY { DEFINER | INVOKER }] 删除 | 同左 |
10 | [WITH [CASCADED | LOCAL] CHECK OPTION] | 全部删除 | 同左 |
11 | SELECT 子查询 | 保持语义输出 | 同左 |
# CREATE INDEX
序号 | MySQL语法/关键字 | YashanDB22.2转换规则 | YashanDB23.1转换规则 |
---|---|---|---|
12 | CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name | 仅支持UNIQUE类型和普通类型 | 同左 |
13 | index_option: { KEY_BLOCK_SIZE [=] value | index_type | WITH PARSER parser_name | COMMENT 'string' | {VISIBLE | INVISIBLE} | ENGINE_ATTRIBUTE [=] 'string' | SECONDARY_ENGINE_ATTRIBUTE [=] 'string' } index_type: USING {BTREE | HASH} algorithm_option: ALGORITHM [=] {DEFAULT | INPLACE | COPY} lock_option: LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE} | 全部删除 | 同左 |
# ALTER TABLE ADD CONSTRAINT / MODIFY NOT NULL
序号 | MySQL语法/关键字 | YashanDB22.2转换规则 | YashanDB23.1转换规则 |
---|---|---|---|
14 | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (key_part,...) [index_option] ... | 删除index_type 和index_option | 同左 |
15 | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX | KEY] [index_name] [index_type] (key_part,...) [index_option] ... | 删除index_type 和index_option | 同左 |
16 | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (col_name,...) reference_definition | 一致 | 同左 |
17 | ADD [CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED] | 删除[[NOT] ENFORCED] | 同左 |
18 | MODIFY COLUMN_NAME DATATYPE NOT NULL | 删除DATATYPE | 同左 |
# CREATE EVENT
MySQL的Event对应对象为YashanDB的JOB,通过查询information_schema.EVENTS视图,将所需要的关键信息进行组装拼接成YashanDB的JOB的创建语句。 所使用到information_schema.EVENTS的关键字段和含义如下表所示。
EVENT_SCHEMA | EVENT_NAME | EVENT_DEFINITION | EVENT_TYPE | EXECUTE_AT | INTERVAL_VALUE | INTERVAL_FIELD | STARTS | ENDS | STATUS | ON_COMPLETION | EVENT_COMMENT |
---|---|---|---|---|---|---|---|---|---|---|---|
Event所属Schema | Event名称 | Event要执行的SQL语句 | event类型 (循环/单词) | 执行时间 | 执行间隔值 | 执行间隔时间的单位 | 该event开始起作用的时间 | 该event结束起作用的时间 | 对象状态 | 完成后是否被删除 | 对象的COMMENT信息 |
对上面的关键信息进行拼接,就可以获取对应的YashanDB的JOB创建语句,YashanDB的JOB创建语句样式如下:
EXEC DBMS_SCHEDULER.CREATE_JOB (
job_name IN VARCHAR, -- 对应字段 EVENT_NAME
job_type IN VARCHAR, -- 对应字段 EVENT_TYPE
job_action IN VARCHAR , -- 对应字段 begin EVENT_DEFINITION end ;
number_of_arguments IN INTEGER DEFAULT 0, -- 无对应字段 保留字段,使用缺省值 0。
start_date IN TIMESTAMP DEFAULT NULL, -- 对应字段 STARTS / EXECUTE_AT
repeat_interval IN VARCHAR DEFAULT NULL, -- 对应字段 INTERVAL_VALUE INTERVAL_FIELD
end_date IN TIMESTAMP DEFAULT NULL, -- 对应字段 ENDS
job_class IN VARCHAR DEFAULT 'DEFAULT_JOB_CLASS', -- 无对应字段 保留字段,使用缺省值 'DEFAULT_JOB_CLASS'。
enabled IN BOOLEAN DEFAULT FALSE, -- 对应字段 STATUS
auto_drop IN BOOLEAN DEFAULT TRUE, -- 对应字段 ON_COMPLETION
comments IN VARCHAR DEFAULT NULL); -- 对应字段 EVENT_COMMENT
Copied!
示例19展示了一个MySQL的Event转换为YashanDB的JOB的样例。
# PLSQL对象处理
对象类型 | 规则 | MySQL语法 | YashanDB预期 |
---|---|---|---|
触发器 | CREATE [DEFINER = user] TRIGGER [IF NOT EXISTS] sp_name | CREATE or replace TRIGGER "SP_NAME" | |
函数 | CREATE [DEFINER = user] FUNCTION [IF NOT EXISTS] sp_name | CREATE or replace FUNCTION "SP_NAME" | |
存储过程 | CREATE [DEFINER = user] PROCEDURE [IF NOT EXISTS] sp_name | CREATE or replace PROCEDURE "SP_NAME" | |
对象名左右两边 | 替换为" 且内部转大写 | ```sql create table xxx( id` int );| sql create table "XXX" ("ID" int );``` |
# 全部示例
# 示例1
-- MySQL
CREATE TEMPORARY TABLE x(id INT)
-- YashanDB22.2预期结果
CREATE GLOBAL TEMPORARY TABLE "X" ("ID" INT);
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例2
-- MySQL
CREATE TABLE MYL.TEST4 (col1 INT REFERENCES MYL.T2(col1) ON
DELETE
SET
null,
col2 INT DEFAULT 1 CHECK(col2 < 30));
-- YashanDB22.2预期结果
CREATE TABLE "MYL"."TEST4" (
"COL1" INT,
"COL2" INT DEFAULT 1
);
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例3
-- MySQL
CREATE TABLE x(id INT auto_increment DEFAULT 'xxx' COMMENT 'xxx');
-- YashanDB22.2预期结果
CREATE SEQUENCE "X_ID_SEQ" INCREMENT BY 1 START WITH 1;
CREATE TABLE "X" (
"ID" INT DEFAULT 'xxx' DEFAULT "X_ID_SEQ".NEXTVAL
);
COMMENT ON COLUMN "X"."ID" IS 'xxx';
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例4
-- MySQL
CREATE TABLE x(id INT auto_increment DEFAULT 'xxx' COMMENT 'xxx') COMMENT 'xxx' auto_increment = 1231 TABLESPACE xxx STORAGE DISK;
-- YashanDB22.2预期结果
CREATE SEQUENCE "X_ID_SEQ" INCREMENT BY 1 START WITH 1231;
CREATE TABLE x (
"ID" INT DEFAULT 'xxx' DEFAULT "X_ID_SEQ".NEXTVAL
) TABLESPACE "XXXDISK";
COMMENT ON COLUMN "X"."ID" IS 'xxx';
COMMENT ON TABLE "X" IS 'xxx';
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例5
-- MySQL
CREATE TABLE x(id INT auto_increment DEFAULT 'xxx' COMMENT 'xxx') COMMENT 'xxx' auto_increment = 1231 TABLESPACE xxx STORAGE DISK;
-- YashanDB22.2预期结果
CREATE SEQUENCE "X_ID_SEQ" INCREMENT BY 1 START WITH 1231;
CREATE TABLE "x" (
"ID" INT DEFAULT 'xxx' DEFAULT "X_ID_SEQ".NEXTVAL
) TABLESPACE "XXXDISK";
COMMENT ON COLUMN "X"."ID" IS 'xxx';
COMMENT ON TABLE "X" IS 'xxx';
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例6
-- MySQL
CREATE TABLE th (id INT, name VARCHAR(30), adate DATE)
PARTITION BY LIST(YEAR(adate))
(
PARTITION p1999 VALUES IN (1995, 1999, 2003)
DATA DIRECTORY = '/var/appdata/95/data'
INDEX DIRECTORY = '/var/appdata/95/idx',
PARTITION p2000 VALUES IN (1996, 2000, 2004)
DATA DIRECTORY = '/var/appdata/96/data'
INDEX DIRECTORY = '/var/appdata/96/idx' TABLESPACE xxx,
PARTITION p2001 VALUES IN (1997, 2001, 2005)
DATA DIRECTORY = '/var/appdata/97/data'
INDEX DIRECTORY = '/var/appdata/97/idx',
PARTITION p2002 VALUES IN (1998, 2002, 2006)
DATA DIRECTORY = '/var/appdata/98/data'
INDEX DIRECTORY = '/var/appdata/98/idx'
);
-- YashanDB22.2预期结果
CREATE TABLE "TH" (
"ID" INT,
"NAME" VARCHAR(30 CHAR),
"ADATE" DATE
)
PARTITION BY LIST (YEAR("ADATE")) ( PARTITION "P1999" VALUES ((1995), (1999), (2003)) , PARTITION "P2000" VALUES ((1996), (2000), (2004))
TABLESPACE "XXX", PARTITION "P2001" VALUES ((1997), (2001), (2005)) , PARTITION "P2002" VALUES ((1998), (2002), (2006))
);
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例7
-- MySQL
CREATE TABLE ts (id INT, purchased DATE)
PARTITION BY RANGE( YEAR(purchased) )
SUBPARTITION BY HASH( TO_DAYS(purchased) )
SUBPARTITIONS 2 (
PARTITION p0 VALUES LESS THAN (1990),
PARTITION p1 VALUES LESS THAN (2000),
PARTITION p2 VALUES LESS THAN MAXVALUE
);
-- YashanDB22.2预期结果
CREATE TABLE "TS" (
"ID" INT,
"PURCHASED" DATE
)
PARTITION BY RANGE (YEAR("PURCHASED"))
( PARTITION "P0" VALUES LESS THAN (1990) , PARTITION "P1" VALUES LESS THAN (2000) , PARTITION "P2" VALUES LESS THAN (MAXVALUE) );
-- YashanDB23.1预期结果
CREATE TABLE "TS" (
"ID" INT,
"PURCHASED" DATE
)
PARTITION BY RANGE (YEAR("PURCHASED"))
SUBPARTITION BY HASH(TO_DAYS("PURCHASED")) SUBPARTITIONS 2
( PARTITION "P0" VALUES LESS THAN (1990) , PARTITION "P0" VALUES LESS THAN (2000) , PARTITION "P2" VALUES LESS THAN (MAXVALUE) );
-- 同上
Copied!
# 示例8
-- MySQL
CREATE TABLE `test_timestamp`(
id INT ,
t1 TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))
-- YashanDB22.2预期结果
CREATE TABLE "TEST_TIMESTAMP" (
"ID" INT,
"T1" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP()
)
;
CREATE TRIGGER "TEST_TIMESTAMP_T1_TRI"
BEFORE UPDATE ON "TEST_TIMESTAMP"
FOR EACH ROW
BEGIN
IF NOT UPDATING('T1') THEN
:NEW."T1" := CURRENT_TIMESTAMP();
END IF;
END;/
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例9
-- MySQL
CREATE OR replace VIEW v3 (idalias ) AS SELECT id FROM v1 WHERE a > 0
-- YashanDB22.2预期结果
CREATE OR REPLACE VIEW "V3"
AS
SELECT "ID"
FROM "V1"
WHERE "A" > 0;
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例10
-- MySQL
CREATE OR replace VIEW v3 (idalias ) AS SELECT id FROM v1 WHERE a > 0
WITH CASCADED CHECK OPTION;
-- YashanDB22.2预期结果
CREATE OR replace VIEW "V3" ("IDALIAS" ) AS SELECT "ID" FROM "V1" WHERE "A" > 0
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例12
-- MySQL
/*The 1 SQL statement*/
CREATE UNIQUE INDEX xxx ON x(x);
/*The 2 SQL statement*/
CREATE FULLTEXT INDEX xxx ON x(x);
/*The 3 SQL statement*/
CREATE INDEX xxx ON x(x);
-- YashanDB22.2预期结果
/*The 1 SQL statement*/
CREATE UNIQUE INDEX "XXX" ON "X" ("X");
/*The 2 SQL statement*/
CREATE INDEX "XXX" ON "X" ("X");
/*The 3 SQL statement*/
CREATE INDEX "XXX" ON "X" ("X");
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例13
-- MySQL
/*The 1 SQL statement*/
CREATE INDEX id_index ON lookup (id) USING BTREE;
/*The 2 SQL statement*/
CREATE INDEX id_index ON t1 (id) COMMENT 'MERGE_THRESHOLD=40';
-- YashanDB22.2预期结果
/*The 1 SQL statement*/
CREATE INDEX "ID_INDEX" ON "LOOKUP" ("ID");
/*The 2 SQL statement*/
CREATE INDEX "ID_INDEX" ON "T1" ("ID");
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例14
-- MySQL
ALTER TABLE xx ADD PRIMARY USING BTREE (id);
-- YashanDB22.2预期结果
ALTER TABLE "XX" ADD PRIMARY KEY ("ID");
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例15
-- MySQL
ALTER TABLE student ADD CONSTRAINT xx UNIQUE KEY USING BTREE(id) ;
-- YashanDB22.2预期结果
ALTER TABLE "STUDENT" ADD CONSTRAINT "XX" UNIQUE ("ID");
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例17
-- MySQL
ALTER TABLE student ADD CHECK (id>0) ENFORCED ;
-- YashanDB22.2预期结果
ALTER TABLE "STUDENT" ADD CHECK ("ID">0) ;
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例18
-- MySQL
ALTER TABLE X MODIFY ID INT NOT NULL;
-- YashanDB22.2预期结果
ALTER TABLE "X" MODIFY "ID" NOT NULL;
-- YashanDB23.1预期结果
-- 同上
Copied!
# 示例19
-- MySQL
CREATE DEFINER=`root`@`%` EVENT `myevent`
ON SCHEDULE AT '2024-01-09 06:14:00'
ON COMPLETION PRESERVE DISABLE ON SLAVE
DO
UPDATE mytable SET mycol = mycol + 1;
;
-- YashanDB22.2预期结果
EXEC DBMS_SCHEDULER.CREATE_JOB('LSP.myevent',
'PLSQL_BLOCK',
' BEGIN UPDATE mytable SET mycol = mycol + 1 ; END ;' ,
0,
TO_TIMESTAMP('2024-01-09 06:14:00', 'YYYY-MM-DD HH24:MI:SS'),
null,
null,
'DEFAULT_JOB_CLASS',
false,
false,
null);
-- YashanDB23.1预期结果
-- 同上
Copied!